package app.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class DBDataGetterJDBCSiotwx {
	//用于储存配置文件
	private static Properties properties=new Properties();
	//类加载的时候加载配置文件
	static{
		InputStream resourceAsStream = DBDataGetterJDBCSiotwx.class.getResourceAsStream("/jdbc.properties");
		try {
			properties.load(resourceAsStream);
			resourceAsStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * 该方法要连接数据库的地址、用户名、用户密码在meterDBConfig.properties文件中进行配置，并且返回的连接对象是默认不进行自动提交
	 * 
	 * @return 返回一个java.sql.Connection类型的数据库连接对象用于进行数据库的连接
	 */
	private static Connection getConnection() {
		Connection connection = null;
		try {
			// 加载数据库的驱动程序
			Class.forName("com.mysql.cj.jdbc.Driver");
			// 数据库的连接地址
			StringBuilder dburl = new StringBuilder();
			dburl.append(properties.getProperty("dataSource.jdbcUrl"));

			// 获取数据库连接
			connection = DriverManager.getConnection(dburl.toString(),
					properties.getProperty("dataSource.user"),
					properties.getProperty("dataSource.password"));
			// 经连接设置成非自动提交以方便进行出错时候的回滚
			connection.setAutoCommit(false);

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return connection;
	}

	/**
	 * 该方法用来执行不需要返回值的sql语句
	 * 
	 * @param sql
	 *            这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
	 * @return 返回一个int类型的结果，该结果表示执行该语句之后受到影响的数据行数
	 */
	public static int executeSqlWithoutResult(String sql) {
		// 保存执行语句影响到的行数
		int val = 0;
		// 保存一个处理语句
		Statement stm = null;
		// 获取一个数据库连接
		Connection connection = getConnection();
		try {
			// 判断连接是否为空防止发生NPE问题
			if (connection != null) {
				stm = connection.createStatement();
				// 判断处理是否为空防止发生NPE问题
				if (stm != null) {
					if (sql.endsWith(";")) {
						sql=sql.substring(0,sql.length()-1);
					}
					String[] sqls = sql.split(";");
					for(int i=0;i<sqls.length;i++){

						stm.addBatch(sqls[i]);
						if (i%100==0) {
							int[] executeBatch = stm.executeBatch();
							for(int v:executeBatch){
								val+=v;
							}
						}
					}
					int[] executeBatch = stm.executeBatch();
					for(int v:executeBatch){
						val+=v;
					}
//					// 执行sql语句并返回影响的行数
//					val = stm.executeUpdate(sql);
					// 提交操作
					connection.commit();
				}
			}
		} catch (SQLException e) {
			try {// 发生意外情况进行事务回滚
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			try {// 确保关闭处理语句和数据库连接
				stm.close();
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return val;
	}

	/**
	 * 该方法用来执行需要返回结果的sql语句
	 * 
	 * @param sql
	 *            这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
	 * @return 返回一个java.sql.ResultSet类型的结果，该结果表示执行该语句之后返回的结果集合
	 * @throws SQLException
	 */
	public static List<HashMap<String, String>> executeSqlWithResult(String sql) {
		// 保存执行语句后的返回结果集
		ResultSet resultSet = null;
		// 定义一个处理语句
		Statement stm = null;
		// 获取一个数据库连接
		Connection connection = getConnection();
		try {
			// 确保连接不为空防止发生NPE问题
			if (connection != null) {
				stm = connection.createStatement();
				// 确保处理语句不为空防止发生NPE问题
				if (stm != null) {
					resultSet = stm.executeQuery(sql);
					// 提交操作
					connection.commit();
				}
			}
		} catch (SQLException e) {
			try {// 发生意外情况进行事务回滚
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
		List<HashMap<String, String>> resloverResultSet = null;
		try {
			resloverResultSet = resloverResultSet(resultSet);
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			try {
				stm.close();
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		return resloverResultSet;
	}
	/**
	 * 该方法用来执行需要返回结果的sql语句
	 * @param sql 这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
	 * @param pageNum 需要的页
	 * @param pageSize 每页条数
	 * @return 返回一个java.sql.ResultSet类型的结果，该结果表示执行该语句之后返回的结果集合
	 */
	public static List<HashMap<String, String>> executeSqlWithResult(String sql,int pageNum,int pageSize) {
		// 保存执行语句后的返回结果集
		ResultSet resultSet = null;
		// 定义一个处理语句
		Statement stm = null;
		// 获取一个数据库连接
		Connection connection = getConnection();
		try {
			// 确保连接不为空防止发生NPE问题
			if (connection != null) {
				stm = connection.createStatement();
				// 确保处理语句不为空防止发生NPE问题
				if (stm != null) {
					//添加分页部分
					sql+=" OFFSET ("+(pageNum-1)*pageSize+") ROW FETCH NEXT "+pageSize+" rows only";
					resultSet = stm.executeQuery(sql);
					// 提交操作
					connection.commit();
				}
			}
		} catch (SQLException e) {
			try {// 发生意外情况进行事务回滚
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
		List<HashMap<String, String>> resloverResultSet = null;
		try {
			resloverResultSet = resloverResultSet(resultSet);
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			try {
				stm.close();
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		return resloverResultSet;
	}

	/**
	 *  
	 * 
	 * @param resultSet
	 *            sql查询之后返回的结果集合类型为java.sql.ResultSet
	 * @return 返回的list类型的结果集，结果集的元素为map类型的<K,V>对
	 * @throws SQLException
	 */
	private static List<HashMap<String, String>> resloverResultSet(ResultSet resultSet) throws SQLException {
		List<HashMap<String, String>> res = null;
		// 判断参数非空防止发生NPE问题
		if (resultSet != null) {
			res = new ArrayList<>();
			ResultSetMetaData m = resultSet.getMetaData();
			int columnCount = m.getColumnCount();
			while (resultSet.next()) {
				Map<String, String> map = new HashMap<>();
				for (int index = 1; index <= columnCount; index++) {
					map.put(m.getColumnLabel(index), resultSet.getString(index));
				}
				res.add((HashMap<String, String>) map);
			}

		}
		return res;
	}

}
